function init()
    g_ui.importStyle('container')

    connect(Container, {
        onOpen = onContainerOpen,
        onClose = onContainerClose,
        onSizeChange = onContainerChangeSize,
        onUpdateItem = onContainerUpdateItem
    })
    connect(Game, {
        onGameEnd = clean()
    })

    reloadContainers()
end

function terminate()
    disconnect(Container, {
        onOpen = onContainerOpen,
        onClose = onContainerClose,
        onSizeChange = onContainerChangeSize,
        onUpdateItem = onContainerUpdateItem
    })
    disconnect(Game, {
        onGameEnd = clean()
    })
end

function reloadContainers()
    clean()
    for _, container in pairs(g_game.getContainers()) do
        onContainerOpen(container)
    end
end

function clean()
    for containerid, container in pairs(g_game.getContainers()) do
        destroy(container)
    end
end

function destroy(container)
    if container.window then
        container.window:destroy()
        container.window = nil
        container.itemsPanel = nil
    end
end

function refreshContainerItems(container)
    for slot = 0, container:getCapacity() - 1 do
        local itemWidget = container.itemsPanel:getChildById('item' .. slot)
        itemWidget:setItem(container:getItem(slot))
        ItemsDatabase.setRarityItem(itemWidget, container:getItem(slot))
        ItemsDatabase.setTier(itemWidget, container:getItem(slot))
    end

    if container:hasPages() then
        refreshContainerPages(container)
    end
end

function toggleContainerPages(containerWindow, pages)
    containerWindow:getChildById('miniwindowScrollBar'):setMarginTop(pages and 42 or 22)
    containerWindow:getChildById('contentsPanel'):setMarginTop(pages and 42 or 22)
    containerWindow:getChildById('pagePanel'):setVisible(pages)
end

function refreshContainerPages(container)
    local currentPage = 1 + math.floor(container:getFirstIndex() / container:getCapacity())
    local pages = 1 + math.floor(math.max(0, (container:getSize() - 1)) / container:getCapacity())
    container.window:recursiveGetChildById('pageLabel'):setText(string.format('Page %i of %i', currentPage, pages))

    local prevPageButton = container.window:recursiveGetChildById('prevPageButton')
    if currentPage == 1 then
        prevPageButton:setEnabled(false)
    else
        prevPageButton:setEnabled(true)
        prevPageButton.onClick = function()
            g_game.seekInContainer(container:getId(), container:getFirstIndex() - container:getCapacity())
        end
    end

    local nextPageButton = container.window:recursiveGetChildById('nextPageButton')
    if currentPage >= pages then
        nextPageButton:setEnabled(false)
    else
        nextPageButton:setEnabled(true)
        nextPageButton.onClick = function()
            g_game.seekInContainer(container:getId(), container:getFirstIndex() + container:getCapacity())
        end
    end
end

function onContainerOpen(container, previousContainer)
    local containerWindow
    if previousContainer then
        containerWindow = previousContainer.window
        previousContainer.window = nil
        previousContainer.itemsPanel = nil
    else
        containerWindow = g_ui.createWidget('ContainerWindow')
    end
    containerWindow:setId('container' .. container:getId())
    local containerPanel = containerWindow:getChildById('contentsPanel')
    local containerItemWidget = containerWindow:getChildById('containerItemWidget')
    containerWindow.onClose = function()
        g_game.close(container)
        containerWindow:hide()
    end

    -- this disables scrollbar auto hiding
    local scrollbar = containerWindow:getChildById('miniwindowScrollBar')
    scrollbar:mergeStyle({
        ['$!on'] = {}
    })

    local upButton = containerWindow:getChildById('upButton')
    upButton.onClick = function()
        g_game.openParent(container)
    end
    upButton:setVisible(container:hasParent())

    local name = container:getName()
    name = name:sub(1, 1):upper() .. name:sub(2)

    if name:len() > 11 then
        name = string.sub(name, 1, #name - 3)
        name = name .. "..."
    end

    containerWindow:setText(name)

    containerItemWidget:setItem(container:getContainerItem())
    containerItemWidget:setPhantom(true)

    containerPanel:destroyChildren()
    for slot = 0, container:getCapacity() - 1 do
        local itemWidget = g_ui.createWidget('Item', containerPanel)
        itemWidget:setId('item' .. slot)
        itemWidget:setItem(container:getItem(slot))
        ItemsDatabase.setRarityItem(itemWidget, container:getItem(slot))
        ItemsDatabase.setTier(itemWidget, container:getItem(slot))
        itemWidget:setMargin(0)
        itemWidget.position = container:getSlotPosition(slot)

        if not container:isUnlocked() then
            itemWidget:setBorderColor('red')
        end
    end

    container.window = containerWindow
    container.itemsPanel = containerPanel

    toggleContainerPages(containerWindow, container:hasPages())
    refreshContainerPages(container)

    local layout = containerPanel:getLayout()
    local cellSize = layout:getCellSize()
    containerWindow:setContentMinimumHeight(cellSize.height)
    containerWindow:setContentMaximumHeight(cellSize.height * layout:getNumLines() + 15)

    if not previousContainer then
        local panel = modules.game_interface.findContentPanelAvailable(containerWindow, cellSize.height)
        panel:addChild(containerWindow)

        if modules.client_options.getOption('openMaximized') then
            containerWindow:setContentHeight(cellSize.height * layout:getNumLines())
        else
            local filledLines = math.max(math.ceil(container:getItemsCount() / layout:getNumColumns()), 1)
            containerWindow:setContentHeight(filledLines * cellSize.height)
        end
    end

    containerWindow:setup()
end

function onContainerClose(container)
    destroy(container)
end

function onContainerChangeSize(container, size)
    if not container.window then
        return
    end
    refreshContainerItems(container)
end

function onContainerUpdateItem(container, slot, item, oldItem)
    if not container.window then
        return
    end
    local itemWidget = container.itemsPanel:getChildById('item' .. slot)
    itemWidget:setItem(item)
end
